home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- mark.c
-
- This module handles marking articles read and unread.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
- #include <stdio.h>
- #include <ctype.h>
-
- #include "glob.h"
- #include "child.h"
- #include "mark.h"
- #include "news.h"
- #include "wind.h"
- #include "subject.h"
- #include "memutil.h"
- #include "header.h"
- #include "dialog.h"
- #include "group.h"
-
-
-
- /*----------------------------------------------------------------------------
- FindParentCell
-
- Locate the parent cell in a list window given an index in a group or
- subject array for the window.
-
- Entry: wind = pointer to group or subject window.
- index = index in group or subject array.
-
- Exit: function result = true if cell found.
- *theCell = the cell in the window list corresponding to
- the indexed element of the group or subject array.
- ----------------------------------------------------------------------------*/
-
- Boolean FindParentCell (WindowPtr wind, short index, Cell *theCell)
- {
- TWindow **info;
- ListHandle theList;
- short numCells, i;
- short *pCells;
-
- info = (TWindow**)GetWRefCon(wind);
- theList = (**info).theList;
- numCells = (**theList).dataBounds.bottom;
- pCells = (short*)*((**theList).cells);
- for (i = 0; i < numCells; i++) {
- if (*pCells == index) {
- SetPt(theCell, 0, i);
- return true;
- }
- pCells++;
- }
- return false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AppendUnreadRange
-
- Append a range of unread messages to the end of the unread list for
- a group.
-
- Entry: first = number of first unread article in range.
- last = number of last unread article in range.
- *theGroup = group info record for group.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr AppendUnreadRange (long first, long last, TGroup *theGroup)
- {
- TUnread **unread, **lastRec, **nextRec;
- OSErr err = noErr;
-
- lastRec = theGroup->unread;
- if (lastRec != nil) {
- while (true) {
- nextRec = (**lastRec).next;
- if (nextRec == nil) break;
- lastRec = nextRec;
- }
- }
-
- if (lastRec != nil && (**lastRec).lastUnread + 1 == first) {
- (**lastRec).lastUnread = last;
- } else {
- err = MyNewHandleCritical(sizeof(TUnread), &unread);
- if (err != noErr) return err;
- (**unread).firstUnread = first;
- (**unread).lastUnread = last;
- (**unread).next = nil;
- if (lastRec == nil) {
- theGroup->unread = unread;
- } else {
- (**lastRec).next = unread;
- }
- }
- theGroup->numUnread += last - first + 1;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkOneRead
-
- Mark a single article in a specified group as being read.
-
- Entry: theGroup = group record.
- number = article number to mark read.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MarkOneRead (TGroup *theGroup, long number)
- {
- TUnread **unread, **newUnread, **prevUnread;
- OSErr err = noErr;
-
- for (unread = prevUnread = theGroup->unread;
- unread != nil &&
- !(number >= (**unread).firstUnread && number <= (**unread).lastUnread);
- prevUnread = unread, unread = (**unread).next) /* do nothing */ ;
-
- if (unread == nil) return noErr; /* already read */
-
- if (number == (**unread).firstUnread || number == (**unread).lastUnread) {
- if (number == (**unread).firstUnread) {
- (**unread).firstUnread++;
- } else {
- (**unread).lastUnread--;
- }
- if ((**unread).firstUnread > (**unread).lastUnread) {
- if (unread != prevUnread) {
- (**prevUnread).next = (**unread).next;
- } else {
- theGroup->unread = (**unread).next;
- }
- MyDisposeHandle(unread);
- }
- } else {
- /* split this one in half */
- err = MyNewHandleCritical(sizeof(TUnread), &newUnread);
- if (err != noErr) return err;
- (**newUnread).next = (**unread).next;
- (**unread).next = newUnread;
- (**newUnread).lastUnread = (**unread).lastUnread;
- (**newUnread).firstUnread = number + 1;
- (**unread).lastUnread = number - 1;
- }
- theGroup->numUnread -= 1;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkOneUnread
-
- Mark a single article in a specified group as being unread.
-
- Entry: theGroup = group record.
- number = article number to mark unread.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MarkOneUnread (TGroup *theGroup, long number)
- {
- TUnread **unread, **newUnread, **prevUnread;
- OSErr err = noErr;
-
- for (unread = prevUnread = theGroup->unread;
- unread != nil && number > (**unread).lastUnread;
- prevUnread = unread, unread = (**unread).next) /* do nothing */ ;
-
- if (unread != nil && number >= (**unread).firstUnread) return noErr; /* already unread */
-
- if (unread == nil) {
- /* insert at end of list, after prevUnread. */
- if (prevUnread != nil && (**prevUnread).lastUnread == number-1) {
- (**prevUnread).lastUnread++;
- } else {
- err = MyNewHandleCritical(sizeof(TUnread), &newUnread);
- if (err != noErr) return err;
- (**newUnread).firstUnread = (**newUnread).lastUnread = number;
- (**newUnread).next = nil;
- if (prevUnread == nil) {
- theGroup->unread = newUnread;
- } else {
- (**prevUnread).next = newUnread;
- }
- }
- } else if (unread == prevUnread) {
- /* insert at beginning of list, before unread. */
- if ((**unread).firstUnread == number+1) {
- (**unread).firstUnread--;
- } else {
- err = MyNewHandleCritical(sizeof(TUnread), &newUnread);
- if (err != noErr) return err;
- (**newUnread).firstUnread = (**newUnread).lastUnread = number;
- (**newUnread).next = unread;
- theGroup->unread = newUnread;
- }
- } else {
- /* insert in middle of list, between prevUnread and unread. */
- if ((**prevUnread).lastUnread == number-1 ||
- (**unread).firstUnread == number+1)
- {
- if ((**prevUnread).lastUnread == number-1) {
- (**prevUnread).lastUnread++;
- } else {
- (**unread).firstUnread--;
- }
- if ((**prevUnread).lastUnread >= (**unread).firstUnread - 1) {
- /* join two blocks together */
- (**prevUnread).lastUnread = (**unread).lastUnread;
- (**prevUnread).next = (**unread).next;
- MyDisposeHandle(unread);
- }
- } else {
- err = MyNewHandleCritical(sizeof(TUnread), &newUnread);
- if (err != noErr) return err;
- (**newUnread).firstUnread = (**newUnread).lastUnread = number;
- (**prevUnread).next = newUnread;
- (**newUnread).next = unread;
- }
- }
- theGroup->numUnread += 1;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AdjustUnreadList
-
- Trim the unread list for a group to include just articles in the range
- [firstMess, lastMess].
-
- Entry: theGroup = pointer to group record.
- ----------------------------------------------------------------------------*/
-
- void AdjustUnreadList (TGroup *theGroup)
- {
- TUnread **prev, **cur;
-
- /* Delete all unread ranges which come before firstMess. */
-
- cur = theGroup->unread;
- while (cur && (**cur).lastUnread < theGroup->firstMess) {
- prev = cur;
- cur = (**cur).next;
- MyDisposeHandle(prev);
- }
- theGroup->unread = cur;
-
- /* If necessary, trim the first unread range to begin at firstMess. */
-
- if (cur && (**cur).firstUnread < theGroup->firstMess)
- (**cur).firstUnread = theGroup->firstMess;
-
- /* Leave alone all unread ranges which come before lastMess. */
-
- prev = nil;
- while (cur && (**cur).firstUnread <= theGroup->lastMess) {
- prev = cur;
- cur = (**cur).next;
- }
-
- /* If necessary, trim the last unread range to end at lastMess. */
-
- if (prev && (**prev).lastUnread > theGroup->lastMess)
- (**prev).lastUnread = theGroup->lastMess;
- if (prev) {
- (**prev).next = nil;
- } else {
- theGroup->unread = nil;
- }
-
- /* Delete the remaining unread ranges, which all come after lastMess. */
-
- while (cur) {
- prev = cur;
- cur = (**cur).next;
- MyDisposeHandle(prev);
- }
-
- /* Recalculate numUnread. */
-
- theGroup->numUnread = 0;
- cur = theGroup->unread;
- while (cur) {
- theGroup->numUnread += (**cur).lastUnread - (**cur).firstUnread + 1;
- cur = (**cur).next;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- UpdateUnreadList
-
- Update the unread list for a group in a user group list window to
- match the read/unread article marks in the corresponding open
- subject window.
-
- Entry: wind = pointer to subject window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr UpdateUnreadList (WindowPtr wind)
- {
- long tmpFirst,tmpLast,i;
- TGroup theGroup,**groupArray;
- TSubject **subjectArray;
- TWindow **info,**parentInfo;
- short index, numSubjectsInList;
- WindowPtr parentWindow;
- long firstFetched;
- TUnread **unread, **prevUnread=nil, **nextUnread;
- long **sortByNumber;
- TSubject *p, *q;
- long *x;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- index = (**info).parentGroup;
- subjectArray = (**info).subjectArray;
- sortByNumber = (**info).sortByNumber;
- numSubjectsInList = (**info).numSubjectsInList;
- parentWindow = (**info).parentWindow;
- parentInfo = (TWindow**)GetWRefCon(parentWindow);
- if ((**parentInfo).groupKind != kUserGroup) return noErr;
- groupArray = (**parentInfo).groupArray;
- theGroup = (*groupArray)[index];
-
- /* Truncate the unread list for the group so that the unread list
- includes only articles which were not fetched from the server
- (articles with numbers less than firstFetched). */
-
- firstFetched = (**info).firstFetched;
- unread = theGroup.unread;
- theGroup.numUnread = 0;
- while (unread != nil) {
- if (firstFetched <= (**unread).lastUnread) break;
- theGroup.numUnread += (**unread).lastUnread - (**unread).firstUnread + 1;
- prevUnread = unread;
- unread = (**unread).next;
- }
- if (unread != nil) {
- if ((**unread).firstUnread < firstFetched) {
- (**unread).lastUnread = firstFetched-1;
- theGroup.numUnread += firstFetched - (**unread).firstUnread;
- prevUnread = unread;
- unread = (**unread).next;
- (**prevUnread).next = nil;
- } else {
- if (prevUnread == nil) {
- theGroup.unread = nil;
- } else {
- (**prevUnread).next = nil;
- }
- }
- while (unread != nil) {
- nextUnread = (**unread).next;
- MyDisposeHandle(unread);
- unread = nextUnread;
- }
- }
-
- (**parentInfo).changed = true;
-
- /* Walk the article list for the subject window in increasing order
- by article number. While the article numbers are less that firstFetched,
- individually mark them read or unread in the group's unread list.
- Note that any such articles came from the article cache, not from
- the server. */
-
- for (i = 0; i < numSubjectsInList; i++) {
- x = *sortByNumber + i;
- p = (TSubject*)((char*)*subjectArray + *x);
- if (p->number >= firstFetched) break;
- if (p->read) {
- err = MarkOneRead(&theGroup, p->number);
- } else {
- err = MarkOneUnread(&theGroup, p->number);
- }
- if (err != noErr) return err;
- }
-
- /* Walk the rest of the article list for the subject window in increasing
- order by article number and append new unread article ranges to the end
- of the unread list for the group. */
-
- tmpFirst = -1;
-
- for (; i < numSubjectsInList; i++) {
- x = *sortByNumber + i;
- p = (TSubject*)((char*)*subjectArray + *x);
- q = (TSubject*)((char*)*subjectArray + *(x+1));
- if (!p->read && i < numSubjectsInList-1 && q->number - p->number > 1) {
- if (tmpFirst == -1) tmpFirst = p->number;
- err = AppendUnreadRange(tmpFirst, p->number, &theGroup);
- if (err != noErr) return err;
- tmpFirst = -1;
- } else if (tmpFirst == -1 && !p->read) {
- tmpFirst = tmpLast = p->number;
- } else if (tmpFirst != -1 && !p->read) {
- tmpLast = p->number;
- } else if (tmpFirst != -1 && p->read) {
- err = AppendUnreadRange(tmpFirst, tmpLast, &theGroup);
- if (err != noErr) return err;
- tmpFirst = -1;
- }
- }
- if (tmpFirst != -1) {
- err = AppendUnreadRange(tmpFirst, tmpLast, &theGroup);
- if (err != noErr) return err;
- }
-
- (*groupArray)[index] = theGroup;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AdjustGroupUnreadCount
-
- Adjust the number of unread articles for a group in a parent group list
- window when one or more subjects in a subject list window have been
- marked read or unread.
-
- Entry: wind = pointer to subject window.
- deltaUnread = change in number of unread articles for group.
- ----------------------------------------------------------------------------*/
-
- static void AdjustGroupUnreadCount (WindowPtr wind, short deltaUnread)
- {
- WindowPtr parent;
- TWindow **info, **parentInfo;
- TGroup **parentGroupArray;
- ListHandle parentList;
- long numUnread;
- short index;
- Cell theCell;
-
- if (deltaUnread == 0) return;
- info = (TWindow**)GetWRefCon(wind);
- parent = (**info).parentWindow;
- parentInfo = (TWindow**)GetWRefCon(parent);
- if ((**parentInfo).groupKind != kUserGroup) return;
- parentGroupArray = (**parentInfo).groupArray;
- parentList = (**parentInfo).theList;
- index = (**info).parentGroup;
- if (FindParentCell(parent, index, &theCell)) {
- numUnread = (*parentGroupArray)[index].numUnread;
- numUnread += deltaUnread;
- if (numUnread < 0) numUnread = 0;
- (*parentGroupArray)[index].numUnread = numUnread;
- (*parentGroupArray)[index].onlyRedrawCount = true;
- LDraw(theCell, parentList);
- (*parentGroupArray)[index].onlyRedrawCount = false;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- AdjustArticleWindowTitle
-
- Mark an article window read or unread.
-
- Entry: wind = pointer to article window.
- read = true to mark read, false to mark unread.
- ----------------------------------------------------------------------------*/
-
- static void AdjustArticleWindowTitle (WindowPtr wind, Boolean read)
- {
- Str255 title;
-
- GetWTitle(wind,title);
- if (read) {
- if (title[1] == checkMark) return;
- if (*title == 255) *title = 254;
- BlockMoveData(title+1, title+2, *title);
- title[1] = checkMark;
- (*title)++;
- } else {
- if (title[1] != checkMark) return;
- (*title)--;
- BlockMoveData(title+2, title+1, *title);
- }
- SetWTitle(wind,title);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkSubjectCell
-
- Mark a single cell in a subject window read or unread. Any open child window
- of the cell is also marked. If the cell is collapsed, all the articles in the
- thread are marked, as are any open children.
-
- Entry: wind = pointer to subject window.
- theCell = cell in subject window to be marked.
- read = true to mark read, false to mark unread.
-
- Exit: *numMarked = number of articles marked.
- ----------------------------------------------------------------------------*/
-
- static void MarkSubjectCell (WindowPtr wind, Cell theCell, Boolean read, short *numMarked)
- {
- WindowPtr child;
- TWindow **info;
- ListHandle theList;
- TSubject **subjectArray;
- short index, cellDataLen, nextInThread;
-
- *numMarked = 0;
- info = (TWindow**)GetWRefCon(wind);
- theList = (**info).theList;
- subjectArray = (**info).subjectArray;
- cellDataLen = 2;
- LGetCell(&index, &cellDataLen, theCell, theList);
- if ((*subjectArray)[index].read != read) {
- (*subjectArray)[index].read = read;
- RedrawSubjectWindowUnreadCount(wind);
- (*numMarked)++;
- }
- child = FindChildByIndex(wind, index);
- if (child != nil) AdjustArticleWindowTitle(child, read);
- if ((*subjectArray)[index].collapsed) {
- nextInThread = (*subjectArray)[index].nextInThread;
- while (nextInThread != -1) {
- if ((*subjectArray)[nextInThread].read != read) {
- (*subjectArray)[nextInThread].read = read;
- RedrawSubjectWindowUnreadCount(wind);
- (*numMarked)++;
- }
- child = FindChildByIndex(wind, nextInThread);
- if (child != nil) AdjustArticleWindowTitle(child, read);
- nextInThread = (*subjectArray)[nextInThread].nextInThread;
- }
- }
- (*subjectArray)[index].onlyRedrawCheck = true;
- LDraw(theCell, theList);
- (*subjectArray)[index].onlyRedrawCheck = false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkSubjectCellRead
-
- Mark a single subject cell read.
-
- Mark a single cell in a subject window read. Any open child window
- of the cell is also marked. If the cell is collapsed, all the articles in the
- thread are marked, as are any open children. The unread count for the group
- is adjusted.
-
- Entry: wind = pointer to subject window.
- theCell = cell in subject window to be marked read.
- ----------------------------------------------------------------------------*/
-
- void MarkSubjectCellRead (WindowPtr wind, Cell theCell)
- {
- short numMarked;
-
- MarkSubjectCell(wind, theCell, true, &numMarked);
- AdjustGroupUnreadCount(wind, -numMarked);
- }
-
-
-
-
- /*----------------------------------------------------------------------------
- MarkOneXref
-
- Mark a single cross-referenced message in a specified group as
- being read or unread.
-
- Entry: groupName = name of group.
- number = article number to mark read.
- wind = pointer to group window.
- read = true to mark read, false to mark unread.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MarkOneXref (char *groupName, long number, WindowPtr wind,
- Boolean read)
- {
- TWindow **info, **childInfo;
- TGroup theGroup, **groupArray;
- ListHandle theList, childList;
- TSubject **subjectArray, *pSubject;
- Cell theCell, childCell;
- short index, childIndex, cellDataLen, numCells, numSubjects;
- WindowPtr child, grandChild;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- theList = (**info).theList;
- groupArray = (**info).groupArray;
- numCells = (**theList).dataBounds.bottom;
- theCell.h = 0;
- for (theCell.v = 0; theCell.v < numCells; theCell.v++) {
- cellDataLen = 2;
- LGetCell(&index, &cellDataLen, theCell, theList);
- if (strcmp(*gGroupNames + (*groupArray)[index].nameOffset,
- groupName) == 0) break;
- }
- if (theCell.v >= numCells) return noErr;
- child = FindChild(wind, theCell);
- if (child != nil) {
- childInfo = (TWindow**)GetWRefCon(child);
- childList = (**childInfo).theList;
- subjectArray = (**childInfo).subjectArray;
- numSubjects = (**childInfo).numSubjects;
- pSubject = *subjectArray;
- for (childIndex = 0; childIndex < numSubjects; childIndex++) {
- if (pSubject->number == number && pSubject->inList) break;
- pSubject++;
- }
- if (childIndex >= numSubjects) return noErr;
- if ((*subjectArray)[childIndex].read != read) {
- (*subjectArray)[childIndex].read = read;
- RedrawSubjectWindowUnreadCount(child);
- if ((*subjectArray)[childIndex].collapsed)
- childIndex = (*subjectArray)[childIndex].threadHeadIndex;
- if (!FindParentCell(child, childIndex, &childCell)) return noErr;
- (*subjectArray)[childIndex].onlyRedrawCheck = true;
- LDraw(childCell, childList);
- (*subjectArray)[childIndex].onlyRedrawCheck = false;
- (*groupArray)[index].numUnread += read ? -1 : 1;
- (*groupArray)[index].onlyRedrawCount = true;
- LDraw(theCell, theList);
- (*groupArray)[index].onlyRedrawCount = false;
- grandChild = FindChildByIndex(child, childIndex);
- if (grandChild != nil) AdjustArticleWindowTitle(grandChild, read);
- }
- } else {
- theGroup = (*groupArray)[index];
- if (read) {
- err = MarkOneRead(&theGroup, number);
- } else {
- err = MarkOneUnread(&theGroup, number);
- }
- if (err != noErr) return err;
- (*groupArray)[index] = theGroup;
- (*groupArray)[index].onlyRedrawCount = true;
- LDraw(theCell, theList);
- (*groupArray)[index].onlyRedrawCount = false;
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkXrefs
-
- Mark articles which appear in multiple newsgroups as read or unread in
- all of the groups.
-
- Entry: wind = pointer to article window.
- read = true to mark read, false to mark unread
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MarkXrefs (WindowPtr wind, Boolean read)
- {
- TWindow **info, **parentInfo, **grandParentInfo;
- WindowPtr parent, grandParent;
- Handle xrefs;
- CStr255 groupName;
- char *p, *pEnd, *groupNameStart;
- long offset, len, number, groupNameLen;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- if ((**info).kind != kArticle) return noErr;
- parent = (**info).parentWindow;
- if (parent == nil) return noErr;
- parentInfo = (TWindow**)GetWRefCon(parent);
- grandParent = (**parentInfo).parentWindow;
- grandParentInfo = (TWindow**)GetWRefCon(grandParent);
- if ((**grandParentInfo).groupKind != kUserGroup) return noErr;
-
- err = FindHeaderHandle((**info).fullText, "Xref", &xrefs);
- if (err != noErr) goto exit;
- if (xrefs == nil) return noErr;
- len = MyGetHandleSize(xrefs);
-
- /* Skip over site name */
-
- p = *xrefs;
- pEnd = p + MyGetHandleSize(xrefs);
- while (p < pEnd && *p != ' ') p++;
-
- /* parse xrefed group:number pairs */
-
- while (p < pEnd) {
- while (p < pEnd && isLWSP(*p)) p++;
- groupNameStart = p;
- while (p < pEnd && *p != ':') p++;
- if (p >= pEnd) break;
- groupNameLen = p - groupNameStart;
- if (groupNameLen > 255) break;
- if (groupNameLen == 0) break;
- BlockMoveData(groupNameStart, groupName, groupNameLen);
- groupName[groupNameLen] = 0;
- p++;
- if (p >= pEnd) break;
- if (!isdigit(*p)) break;
- number = *p - '0';
- p++;
- while (p < pEnd && isdigit(*p)) {
- number = 10*number + (*p - '0');
- p++;
- }
- offset = p - *xrefs;
- err = MarkOneXref(groupName, number, grandParent, read);
- if (err != noErr) goto exit;
- p = *xrefs + offset;
- pEnd = *xrefs + len;
- }
-
- MyDisposeHandle(xrefs);
- return noErr;
-
- exit:
-
- MyDisposeHandle(xrefs);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkSelectedSubjects
-
- Mark all selected subjects in a subject window read or unread.
-
- Entry: wind = pointer to subject window.
- read = true to mark read, false to mark unread.
- ----------------------------------------------------------------------------*/
-
- static void MarkSelectedSubjects (WindowPtr wind, Boolean read)
- {
- TWindow **info;
- Cell theCell;
- short totMarked = 0, numMarked;
-
- info = (TWindow**)GetWRefCon(wind);
- if ((**info).kind != kSubject) return;
-
- SetPt(&theCell, 0, 0);
- while (LGetSelect(true, &theCell, (**info).theList)) {
- MarkSubjectCell(wind, theCell, read, &numMarked);
- theCell.v++;
- totMarked += numMarked;
- }
- AdjustGroupUnreadCount(wind, read ? -totMarked : totMarked);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkAllSubjects
-
- Mark all subjects in a subject window read or unread.
-
- Entry: wind = pointer to subject window.
- read = true to mark read, false to mark unread.
- ----------------------------------------------------------------------------*/
-
- void MarkAllSubjects (WindowPtr wind, Boolean read)
- {
- TWindow **info;
- Cell theCell;
- ListHandle theList;
- short numCells;
- short totMarked = 0, numMarked;
-
- info = (TWindow**)GetWRefCon(wind);
- theList = (**info).theList;
- numCells = (**theList).dataBounds.bottom;
- theCell.h = 0;
- for (theCell.v = 0; theCell.v < numCells; theCell.v++) {
- MarkSubjectCell(wind, theCell, read, &numMarked);
- totMarked += numMarked;
- }
- AdjustGroupUnreadCount(wind, read ? -totMarked : totMarked);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkArticle
-
- Mark an article window read or unread.
-
- Entry: wind = pointer to article window.
- read = true to mark read, false to mark unread.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MarkArticle (WindowPtr wind, Boolean read)
- {
- WindowPtr parent;
- TWindow **info,**parentInfo;
- Cell theCell;
- ListHandle parentList;
- TSubject **subjectArray;
- short index;
-
- info = (TWindow**)GetWRefCon(wind);
- index = (**info).parentSubject;
- parent = (**info).parentWindow;
- if (parent == nil) return noErr;
- parentInfo = (TWindow**)GetWRefCon(parent);
- subjectArray = (**parentInfo).subjectArray;
- parentList = (**parentInfo).theList;
-
- AdjustArticleWindowTitle(wind, read);
-
- if ((*subjectArray)[index].read != read) {
- (*subjectArray)[index].read = read;
- RedrawSubjectWindowUnreadCount(parent);
- if ((*subjectArray)[index].collapsed) index = (*subjectArray)[index].threadHeadIndex;
- if (FindParentCell(parent, index, &theCell)) {
- (*subjectArray)[index].onlyRedrawCheck = true;
- LDraw(theCell, parentList);
- (*subjectArray)[index].onlyRedrawCheck = false;
- }
- AdjustGroupUnreadCount(parent, read ? -1 : +1);
- }
-
- return MarkXrefs(wind, read);
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkSelectedGroups
-
- Mark all selected groups in a group window read or unread.
-
- Entry: wind = pointer to user group window.
- read = true to mark read, false to mark unread.
- maxUnread = maximum number of articles to mark unread
- if read = false.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr MarkSelectedGroups (WindowPtr wind, Boolean read, long maxUnread)
- {
- WindowPtr child;
- TWindow **info;
- Cell theCell;
- short index, cellDataLen;
- TGroup **groupArray, theGroup;
- ListHandle theList;
- TUnread **pUnreadRec;
- OSErr err = noErr;
- long firstUnread, lastUnread;
-
- info = (TWindow**)GetWRefCon(wind);
- if ((**info).groupKind != kUserGroup) return noErr;
- theList = (**info).theList;
- groupArray = (**info).groupArray;
-
- SetPt(&theCell,0,0);
- while (LGetSelect(true, &theCell, theList)) {
-
- cellDataLen = 2;
- LGetCell(&index, &cellDataLen, theCell, theList);
-
- theGroup = (*groupArray)[index];
-
- DisposeGroupUnreadList(&theGroup);
-
- if (!read) {
- err = MyNewHandle(sizeof(TUnread), &pUnreadRec);
- if (err != noErr) return err;
- firstUnread = theGroup.firstMess;
- lastUnread = theGroup.lastMess;
- if (lastUnread - maxUnread + 1 > firstUnread)
- firstUnread = lastUnread - maxUnread + 1;
- (**pUnreadRec).firstUnread = firstUnread;
- (**pUnreadRec).lastUnread = lastUnread;
- (**pUnreadRec).next = nil;
- theGroup.unread = pUnreadRec;
- theGroup.numUnread = lastUnread - firstUnread + 1;
- }
-
- (*groupArray)[index] = theGroup;
-
- (*groupArray)[index].onlyRedrawCount = true;
- LDraw(theCell, theList);
- (*groupArray)[index].onlyRedrawCount = false;
-
- child = FindChild(wind, theCell);
- if (child != nil) MarkAllSubjects(child, read);
-
- (**info).changed = true;
-
- theCell.v++;
- }
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MarkThread
-
- Mark all the articles in a thread read or unread.
-
- Entry: wind = pointer to subjet window.
- threadHeadIndex = index in subject array of first article
- in thread.
- read = true to mark read, false to mark unread.
- ----------------------------------------------------------------------------*/
-
- void MarkThread (WindowPtr wind, short threadHeadIndex, Boolean read)
- {
- TWindow **info;
- TSubject **subjectArray;
- WindowPtr child;
- short index, numMarked = 0;
- Boolean collapsed;
- Cell theCell;
- ListHandle theList;
-
- info = (TWindow**)GetWRefCon(wind);
- theList = (**info).theList;
- subjectArray = (**info).subjectArray;
- collapsed = (*subjectArray)[threadHeadIndex].collapsed;
- if (!FindParentCell(wind, threadHeadIndex, &theCell)) return;
- index = threadHeadIndex;
- while (index != -1) {
- if ((*subjectArray)[index].read != read) {
- (*subjectArray)[index].read = read;
- numMarked++;
- child = FindChildByIndex(wind, index);
- if (child != nil) AdjustArticleWindowTitle(child, read);
- if (!collapsed) {
- (*subjectArray)[index].onlyRedrawCheck = true;
- LDraw(theCell, theList);
- (*subjectArray)[index].onlyRedrawCheck = false;
- }
- }
- if (!collapsed) theCell.v++;
- index = (*subjectArray)[index].nextInThread;
- }
- if (collapsed) {
- (*subjectArray)[threadHeadIndex].onlyRedrawCheck = true;
- LDraw(theCell, theList);
- (*subjectArray)[threadHeadIndex].onlyRedrawCheck = false;
- }
-
- AdjustGroupUnreadCount(wind, read ? -numMarked : numMarked);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoMarkCommand
-
- Handle the "Mark Read" and "Mark Unread" commands.
-
- Entry: wind = pointer to group, subject, or article window.
- read = true to mark read, false to mark unread.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoMarkCommand (WindowPtr wind, Boolean read)
- {
- TWindow **info;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
-
- switch ((**info).kind) {
- case kGroup:
- if ((**info).groupKind == kUserGroup) {
- err = MarkSelectedGroups(wind, read, 0x70000000);
- if (err != noErr) return err;
- }
- break;
- case kSubject:
- MarkSelectedSubjects(wind, read);
- break;
- case kArticle:
- err = MarkArticle(wind, read);
- if (err != noErr) return err;
- break;
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoMarkOthersRead
-
- Handle the "Mark Others Read" command.
-
- Entry: wind = pointer to subject window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoMarkOthersRead (WindowPtr wind)
- {
- TWindow **info;
- ListHandle theList;
- Cell theCell;
- short totMarked = 0, numMarked;
- short *p, *pEnd;
- char state;
-
- info = (TWindow**)GetWRefCon(wind);
- if ((**info).kind != kSubject) return noErr;
- theList = (**info).theList;
-
- SetPt(&theCell, 0, 0);
- state = MyHGetState(theList);
- MyHLock(theList);
- p = (**theList).cellArray;
- pEnd = p + (**theList).dataBounds.bottom;
- while (p < pEnd) {
- if ((*p & 0x8000) == 0) {
- MarkSubjectCell(wind, theCell, true, &numMarked);
- totMarked += numMarked;
- }
- p++;
- theCell.v++;
- }
- MyHSetState(theList, state);
- AdjustGroupUnreadCount(wind, -totMarked);
- return noErr;
- }
-